/*-------------------------------------------------------------------------
 *
 * skey.h
 *	  POSTGRES 扫描关键字定义。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/access/skey.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef SKEY_H
#define SKEY_H

#include "access/attnum.h"
#include "access/stratnum.h"
#include "fmgr.h"


/*
 * ScanKey 表示在表或索引列与常量之间应用的比较运算符。 当它是 ScanKeys 数组的一部分时，比较条件隐式地使用 AND。 索引列是运算符的左侧参数，如果它是二元运算符的话。
 * （该数据结构也可以支持一元可索引运算符；在这种情况下，sk_argument 将不使用。此功能当前未实现。）
 *
 * 对于索引扫描，sk_strategy 和 sk_subtype 必须为运算符正确设置。 在使用 ScanKey 进行堆扫描时，这些字段不使用，可以设置为 InvalidStrategy/InvalidOid。
 *
 * 如果运算符对排序敏感，sk_collation 也必须正确设置。
 *
 * ScanKey 还可以表示 ScalarArrayOpExpr 条件，即 “column op ANY(ARRAY[...])”。 这一点通过 SK_SEARCHARRAY 标志位表示。 sk_argument 不是运算符右侧参数类型的值，而是一组此类值，逐元素比较将使用 OR 连接在一起。
 *
 * ScanKey 还可以表示条件 “column IS NULL” 或 “column IS NOT NULL”；这些情况分别由 SK_SEARCHNULL 和 SK_SEARCHNOTNULL 标志位表示。 参数始终为 NULL，sk_strategy、sk_subtype、sk_collation 和 sk_func 字段不使用（除非由索引 AM 设置）。
 *
 * SK_SEARCHARRAY、SK_SEARCHNULL 和 SK_SEARCHNOTNULL 仅支持索引扫描，而不支持堆扫描；并且并不是所有索引 AM 都支持它们，只有那些分别设置了 amsearcharray 或 amsearchnulls 的。
 *
 * ScanKey 还可以表示排序运算符调用，即排序要求 “ORDER BY indexedcol op constant”。 这看起来与比较运算符相同，只是运算符（通常）不返回布尔值。 我们用 SK_ORDER_BY 标记这样的 ScanKeys。 SK_SEARCHARRAY、SK_SEARCHNULL、SK_SEARCHNOTNULL 不能在这里使用。
 *
 * 注意：在某些地方，ScanKeys 被用作对访问方法支持过程的方便表示。 在这种情况下，sk_strategy/sk_subtype 是没有意义的（但 sk_collation 可以）；并且 sk_func 可能指的是返回布尔值以外的内容的函数。
 */
typedef struct ScanKeyData
{
	int			sk_flags;		/* 标志，请参见下文 */
	AttrNumber	sk_attno;		/* 表或索引列编号 */
	StrategyNumber sk_strategy; /* 运算符策略编号 */
	Oid			sk_subtype;		/* 策略子类型 */
	Oid			sk_collation;	/* 使用的排序规则，如果需要的话 */
	FmgrInfo	sk_func;		/* 调用函数的查找信息 */
	Datum		sk_argument;	/* 要比较的数据 */
} ScanKeyData;

typedef ScanKeyData *ScanKey;

/*
 * 关于行比较：
 *
 * ScanKey 数据结构也支持行比较，即有序元组比较，如 (x, y) > (c1, c2)，拥有 SQL 规范语义
 * “x > c1 或 (x = c1 且 y > c2)”。 请注意，这目前仅在 btree 索引搜索中实现，而不是在堆扫描或其他任何索引
 * 类型中。 行比较由一个“头部” ScanKey 条目加上一个单独的 ScanKeys 数组表示，每个列的行比较。
 * 头部条目具有以下属性：
 *		sk_flags = SK_ROW_HEADER
 *		sk_attno = 行比较的主列的索引列号
 *		sk_strategy = 行比较的 btree 策略代码
 *				（即，< <= > 或 >=）
 *		sk_subtype, sk_collation, sk_func: 不使用
 *		sk_argument: 指向辅助 ScanKey 数组的指针
 * 如果头部是按 attno 排序的 ScanKey 数组的一部分，则
 * 它必须按主列号进行排序。
 *
 * 辅助 ScanKey 数组按行比较的逻辑列顺序出现，这可能与索引列顺序不同。 数组
 * 元素类似于普通的 ScanKey 数组，除了：
 *		sk_flags 必须包括 SK_ROW_MEMBER，并且最后一个元素中必须包含 SK_ROW_END
 *				（需要因为行头部不包括计数）
 *		sk_func 指向 opclass 的 btree 比较支持函数，而不是运算符的实现函数。
 * sk_strategy 在辅助数组的所有元素中必须相同，
 * 即与头部条目中的相同。
 * SK_SEARCHARRAY, SK_SEARCHNULL, SK_SEARCHNOTNULL 不能在这里使用。
 */

/*
 * ScanKeyData sk_flags
 *
 * sk_flags 的位 0-15 保留供系统范围使用（这些位的符号应该在这里定义）。 位 16-31 保留供
 * 单个索引访问方法使用。
 */
#define SK_ISNULL			0x0001	/* sk_argument 为 NULL */
#define SK_UNARY			0x0002	/* 一元运算符（不支持！） */
#define SK_ROW_HEADER		0x0004	/* 行比较头部（见上文） */
#define SK_ROW_MEMBER		0x0008	/* 行比较成员（见上文） */
#define SK_ROW_END			0x0010	/* 最后一行比较成员 */
#define SK_SEARCHARRAY		0x0020	/* scankey 表示 ScalarArrayOp */
#define SK_SEARCHNULL		0x0040	/* scankey 表示 "col IS NULL" */
#define SK_SEARCHNOTNULL	0x0080	/* scankey 表示 "col IS NOT NULL" */
#define SK_ORDER_BY			0x0100	/* scankey 是用于 ORDER BY 操作 */


/*
 * access/common/scankey.c 中函数的原型
 */
extern void ScanKeyInit(ScanKey entry,
						AttrNumber attributeNumber,
						StrategyNumber strategy,
						RegProcedure procedure,
						Datum argument);
extern void ScanKeyEntryInitialize(ScanKey entry,
								   int flags,
								   AttrNumber attributeNumber,
								   StrategyNumber strategy,
								   Oid subtype,
								   Oid collation,
								   RegProcedure procedure,
								   Datum argument);
extern void ScanKeyEntryInitializeWithInfo(ScanKey entry,
										   int flags,
										   AttrNumber attributeNumber,
										   StrategyNumber strategy,
										   Oid subtype,
										   Oid collation,
										   FmgrInfo *finfo,
										   Datum argument);

#endif							/* SKEY_H */
